package com.trade.module.base.service.impl;

import com.trade.module.base.entity.Resource;
import com.trade.module.base.entity.ResourceRole;
import com.trade.module.base.entity.User;
import com.trade.module.base.entity.UserRole;
import com.trade.module.base.repository.ResourceRepository;
import com.trade.module.base.repository.ResourceRoleRepository;
import com.trade.module.base.repository.UserRepository;
import com.trade.module.base.repository.UserRoleRepository;
import com.trade.module.base.service.ResourceService;
import com.trade.common.utils.*;
import com.trade.module.base.vo.ResourceVo;
import lombok.extern.log4j.Log4j;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;

/**
 * Class Description: 资源服务层实现类
 *
 * @Version v1.0 2017/4/22 18:12
 * @JDK version 1.8.0_51
 * @Author zfb
 */
@Log4j
@Service
@Transactional
public class ResourceServiceImpl implements ResourceService{

    /**
     * 注入资源数据持久层
     */
    @Autowired
    private ResourceRepository resourceRepository;

    /**
     * 注入用戶角色数据持久层
     */
    @Autowired
    private UserRoleRepository urRepository;

    /**
     * 注入資源角色数据持久层
     */
    @Autowired
    private ResourceRoleRepository resourceRoleRepository;

    /**
     * 注入用户持久层
     */
    @Autowired
    private UserRepository userRepository;

    private static Map<String,String> resTypeLevelMap = new HashMap<>();
    static {
        resTypeLevelMap.put(Constants.RESOURCE_SYSTEM, Constants.RESOURCE_LEVEL_1);
        resTypeLevelMap.put(Constants.RESOURCE_PLATFORM,Constants.RESOURCE_LEVEL_2);
        resTypeLevelMap.put(Constants.RESOURCE_CATALOG,Constants.RESOURCE_LEVEL_3);
        resTypeLevelMap.put(Constants.RESOURCE_MENU,Constants.RESOURCE_LEVEL_4);
        resTypeLevelMap.put(Constants.RESOURCE_FUNC,Constants.RESOURCE_LEVEL_5);
        resTypeLevelMap.put(Constants.RESOURCE_BTN,Constants.RESOURCE_LEVEL_5);
        resTypeLevelMap.put(Constants.RESOURCE_HTML,Constants.RESOURCE_LEVEL_5);
    }



    @Override
    public List<Resource> findResourceAll() {
        List<SearchFilter> filters = SearchFilter.parse(null);//解析查询条件,自动田间数据状态过滤
        return resourceRepository.findAll(DynamicSpecifications.bySearchFilter(filters, Resource.class));
    }

    @Deprecated
    @Override
    public List<Resource> reslistForClient(String userId, String ip) {
        List<Resource> reslist = new ArrayList<>();
        Set<Resource> resSet = new LinkedHashSet<>();
        //查询用户角色ID集合
        Iterable<UserRole> userRoleit = urRepository.findUserRoleByUserId(userId, Constants.DATA_FLAG_OK, Constants.DATA_FLAG_OK);//多个
        Iterator<UserRole> iterator = userRoleit.iterator();
        if (null != iterator) {
            while (iterator.hasNext()) {
                String userRoleId = iterator.next().getRoleId();
                //1.根据角色ID查询角色所拥有的资源
                //TODO 这里需要进一步判断用户是在外网访问还是内网访问，然后根据用户的网络访问权限获取资源集合
                Iterable<ResourceRole> roleResourceit = resourceRoleRepository.findRoleResourceByRoleId(userRoleId,
                        Constants.DATA_FLAG_OK, Constants.DATA_FLAG_OK);

                Iterator<ResourceRole> roleresit = roleResourceit.iterator();
                //将查询到的角色资源的ID放入到集合中
                Set<String> resIds = new LinkedHashSet<>();
                while (roleresit.hasNext()) {
                    resIds.add(roleresit.next().getResourceId());
                }
                //2.根据资源ID集合查询资源信息
                List<Resource> resourceList = null;
                if (resIds.size() > 0) {
                    resourceList = resourceRepository.findByIdInAndDataFlagOrderByCreateTimeAsc(resIds,Constants.DATA_FLAG_OK);
                }
                Set<String> res3Ids = new LinkedHashSet<String>();
                if (XaUtil.isNotEmpty(resourceList)) {
                    for (Resource resTemp : resourceList) {
                        //是四级资源并且是可显示的资源将被查询出来
                        if (Constants.ISORNOT_IS.equalsIgnoreCase(resTemp.getIsShow())
                                && Constants.RESOURCE_LEVEL_2.equalsIgnoreCase(resTemp.getResLevel())) {
                            res3Ids.add(resTemp.getResParentResourceId());
                            resSet.add(resTemp);
                        }
                    }
                }
                //3.如果要查询的3级资源id不为空，查询三级资源（菜单）
                List<Resource> resource3List = null;
                if (res3Ids.size() > 0) {
                    //resource3Iterable = resourceRepository.findAll(res3Ids);
                    resource3List = resourceRepository.findByIdInAndDataFlagOrderByCreateTimeAsc(res3Ids,
                            Constants.DATA_FLAG_OK);
                }
                Set<String> res2Ids = new LinkedHashSet<String>();
                if (XaUtil.isNotEmpty(resource3List)) {
                    for (Resource resource : resource3List) {
                        if (Constants.ISORNOT_IS.equalsIgnoreCase(resource.getIsShow())) {
                            res2Ids.add(resource.getResParentResourceId());
                            resSet.add(resource);
                        }
                    }
                }

                //4.如果要查询的2级资源id不为空，查询二级资源（目录）
                List<Resource> resource2List = null;
                if (res2Ids.size() > 0) {
                    resource2List = resourceRepository.findByIdInAndDataFlagOrderByCreateTimeAsc(res2Ids,
                            Constants.DATA_FLAG_OK);
                }
                Set<String> res1Ids = new LinkedHashSet<String>();
                if (XaUtil.isNotEmpty(resource2List)) {
                    for (Resource resource : resource2List) {
                        res1Ids.add(resource.getResParentResourceId());
                        resSet.add(resource);
                    }
                }
                //5.如果要查询的1级资源id不为空，查询一级资源（平台）
                List<Resource> resource1List = null;
                if (res1Ids.size() > 0) {
                    resource1List = resourceRepository.findByIdInAndDataFlagOrderByCreateTimeAsc(res1Ids, Constants.DATA_FLAG_OK);
                }
                if (XaUtil.isNotEmpty(resource1List)) {
                    for (Resource resource : resource1List) {
                        resSet.add(resource);
                    }
                }
            }
        }
        reslist.addAll(resSet);
        return reslist;
    }

    /**
     * Method description：添加菜单信息
     *
     * @param resource 资源对象
     * @return Resource
     */
    @Override
    @Transactional
    public Resource save(Resource resource) {
        boolean setcodeResult = getResourceCode(resource);
        Resource resourcePo = null;
        if (setcodeResult){
            List<SearchFilter> filters = SearchFilter.parse(null);
            SearchFilter flagFilter = filters.get(0);
            SearchFilter resParentResourceIdFilter = new SearchFilter("resParentResourceId", SearchFilter.Operator.EQ, resource.getResParentResourceId());
            SearchFilter resTypeFilter = new SearchFilter("resType", SearchFilter.Operator.EQ, resource.getResType());
            SearchFilter resUrlFilter = new SearchFilter("resUrl", SearchFilter.Operator.EQ, resource.getResUrl());
            SearchFilter nameFilter = new SearchFilter("resName", SearchFilter.Operator.EQ, resource.getResName());
            filters.add(resParentResourceIdFilter);
            filters.add(resTypeFilter);
            filters.add(resUrlFilter);
            filters.add(nameFilter);

            if(!resTypeLevelMap.get(resource.getResType()).equals(resource.getResLevel())){
                log.error("类型和级别不相符，添加失败！" );
                return resourcePo;
            }

            List<Resource> exists = resourceRepository.findAll(DynamicSpecifications.bySearchFilter(filters, Resource.class));
            if (null == exists || 0 == exists.size()) {
                flagFilter.value = Constants.DATA_FLAG_DELETE;
                exists = resourceRepository.findAll(DynamicSpecifications.bySearchFilter(filters, Resource.class));
                if (null != exists && exists.size() > 0) {
                    Resource exist = exists.get(0);
                    try {
                        BeanUtil.copyAllProperties(resource, exist);
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("资源数据异常！" + exist);
                        return null;
                    }
                    exist.setDataFlag(Constants.DATA_FLAG_OK);
                    resourcePo = resourceRepository.save(exist);
                    log.debug("更新数据删除状态！" + exist);
                    return resourcePo;
                } else {
                    resourcePo = resourceRepository.save(resource);
                }
                //缓存资源链接到redis
                /*
                Jedis jedis = RedisUtil.getRedis().getWriterPool().getResource();
                jedis.sadd(AuthConf.KEY_BAN_RES_SUFFIX,resourcePo.getResUrl()+"@"+resourcePo.getResMethod());
                */
            } else {
                log.warn("该资源已经存在！" + resource);
            }
        }
        return  resourcePo;
    }

    @Override
    public Resource saveSub(Resource resource) {
        return null;
    }

    @Override
    public List<Resource> findSubRes(String subId) {
        return null;
    }

    @Override
    public boolean update(Resource resource) {
        return false;
    }

    @Override
    public ResourceVo findById(String id) {
        return null;
    }

    @Override
    public ResourceVo startFlagById(String id) {
        return null;
    }

    @Override
    public ResourceVo banFlagById(String id) {
        return null;
    }

    /**
     * 根据父级菜单的ID生成子菜单编码
     * 编码规则：
     * 1.   系统级别编码(m000000000000)
     * 2.	平台级别编码(m001000000000)
     * 3.	基类菜单编码(m001001000000)
     * 4.	子集菜单编码(m001001001000)
     * 5.	按钮级别编码(m001001001001)
     *
     * @param resource 资源
     * @return Boolean
     */
    public Boolean getResourceCode(Resource resource){
        if(XaUtil.isEmpty(resource)){
            log.debug("生成系统菜单编码和菜单级别失败，资源信息为"+resource);
            return false;
        }
        boolean result = false;
        String pId = resource.getResParentResourceId();
        if (XaUtil.isNotEmpty(pId)){
            log.debug("开始生成系统菜单编码和菜单级别，上级菜单ID为： " + pId);
            Resource pResource = resourceRepository.findOne(pId);
            if (XaUtil.isNotEmpty(pResource)){
                resource.setIsShow(pResource.getIsShow());//设置显示属性与父级显示属性一致
                String pEclementCode = pResource.getResElementCode();
                //查找当前父节点下子菜单信息
                List<Resource> resourceNodelist = resourceRepository.findAllResByParentId(pId);
                int resourceCount =XaUtil.isNotEmpty(resourceNodelist) ? (resourceNodelist.size()+1) : 1;
                result = true;
                //根据父级资源编码设置当前资源的级别、编码
                String plevel = pResource.getResLevel();
                if(Constants.RESOURCE_LEVEL_1.equals(plevel)){
                    resource.setResLevel(Constants.RESOURCE_LEVEL_2);
                    resource.setResElementCode(pEclementCode.substring(0,1)+String.format("%03d",resourceCount)+"000000000");
                }else if(Constants.RESOURCE_LEVEL_2.equals(plevel)){
                    resource.setResLevel(Constants.RESOURCE_LEVEL_3);
                    resource.setResElementCode(pEclementCode.substring(0,4)+String.format("%03d",resourceCount)+"000000");
                }else if(Constants.RESOURCE_LEVEL_3.equals(plevel)){
                    resource.setResLevel(Constants.RESOURCE_LEVEL_4);
                    resource.setResElementCode(pEclementCode.substring(0,7) + String.format("%03d", resourceCount) + "000");
                }else if(Constants.RESOURCE_LEVEL_4.equals(plevel)){
                    resource.setResLevel(Constants.RESOURCE_LEVEL_5);
                    resource.setResElementCode(pEclementCode.substring(0,10) + String.format("%03d", resourceCount));
                } else {
                    result = false;
                    log.error("生成系统菜单编码和菜单级别失败，上级资源级别定义不正确，上级菜单ID=" + pResource.getId());
                }
                resource.setResRank(resourceCount);
            }else{
                resource.setIsShow(Constants.ISORNOT_IS);
                log.error("生成系统菜单编码和菜单级别失败，菜单无法查到菜单上级资源信息。");
            }
        }else{
            if(resource.getResType()!=null &&resource.getResType().equals(Constants.RESOURCE_SYSTEM)){
                resource.setResLevel(Constants.RESOURCE_LEVEL_1);
                resource.setResElementCode("m000000000000");
                result = true;
            }
            resource.setIsShow(Constants.ISORNOT_IS);
            log.error("生成系统菜单编码和菜单级别失败，系统菜单对象为null或上级菜单ID为null");
        }
        return result;
    }

    @Override
    public int deleteById(String id) {
        return 0;
    }

    /**
     * Method description：根据条件分页查询数据字典
     *
     * @param pageNum           当前页码，为null或者为0将查询所有有效数据
     * @param pageSize           每页查询条数，默认为10
     * @param sortJsonArray      排序的json数组，格式为[{property:"排序字段名",direction:"ASC/DESC"}]，null、空字符串及[]将被认为是不进行排序
     * @param conditionJsonArray 查询条件的json数组，格式为[{property:"字段名",option:"操作类型",value:"值",propertytype:"数据类型"}]
     *                           其中option的值有EQ(等于), IN(在值数组中), ISNULL(非空), LIKE(包含), GT(大于), LT(小于), GTE(大于等于),
     *                           LTE(小于等于), NE(不等于),LIKEIGNORE(包含，忽略大小写)
     *                           propertytype为DATETIME或DATE，DATETIME值格式为YYYY-MM-dd HH:mm:ss，DATE值格式为YYYY-MM-dd
     *                           <p/>
     *                           conditionJsonArray为null、空字符串及[]将被认为是不进行条件过滤
     * @return PageBean
     */
    @Override
    public PageBean<ResourceVo> findResourcePageByCondition(Integer pageNum,
                                                            Integer pageSize,
                                                            String sortJsonArray,
                                                            String conditionJsonArray) {
        List<SearchFilter> filters = SearchFilter.parse(conditionJsonArray);//解析查询条件
        PageBeanFactory pageBeanFactory = PageBeanFactory.getInstance();//声明返回结果构建工厂

        //如果nextPage为null或者为0则查询所有数据，否则进行分页查询
        if ((null != pageNum) && (pageNum.intValue() >= 0)) {
            //获取分页查询信息，进行分页查询并返回结果
            Pageable pageable = WebUitl.buildPageRequest(pageNum.intValue(), pageSize, sortJsonArray);//声明分页
            Page<Resource> resourcePage = resourceRepository.findAll(DynamicSpecifications.bySearchFilter(filters, Resource.class), pageable);

            List<ResourceVo> resVoList = new ArrayList<>();
            //判断查询结果是否为空。
            if ((resourcePage != null) && (resourcePage.getContent() != null)
                    && (resourcePage.getContent().size() > 0)) {
                List<Resource> resourceList = resourcePage.getContent();
                resVoList = poToVo(resourceList);
            }
            return pageBeanFactory.getPageBeanByPage(resourcePage, resVoList);
        } else {
            //获取排序信息，如果无排序信息则直接根据条件查询，如果有排序信息则根据条件排序查询
            Sort sort = WebUitl.buildSort(sortJsonArray);
            List<Resource> resourceList;
            if (null == sort) {
                resourceList = resourceRepository.findAll(DynamicSpecifications.bySearchFilter(filters, Resource.class));
            } else {
                resourceList = resourceRepository.findAll(DynamicSpecifications.bySearchFilter(filters, Resource.class), sort);
            }
            List<ResourceVo> resVoList = poToVo(resourceList);
            // 返回结果
            return pageBeanFactory.getPageBeanByList(resVoList);
        }
    }

    @Override
    public List<String> findResourceUrlByRoleId(String roleId) {
        return null;
    }

    @Override
    public List<Resource> findResByRoleId(String roleId, String resFlag) {
        return null;
    }

    @Override
    public List<Resource> findBtnByUrl(String userId, String url) {
        return null;
    }

    /**
     * po—>vo
     * @param resList 资源list
     * @return List<ResourceVo> 资源voList
     */
    private List<ResourceVo> poToVo(List<Resource> resList) {
        List<ResourceVo> resVoList = new ArrayList<>();
        //存放更新人Id
        Set<String> ids = new HashSet<String>();
        //获取查询结果的所有更新人ID，并查询出所有包含ID的user，封装id与用户名到Map中
        for (Resource res:resList) {
            if (XaUtil.isNotEmpty(res.getModifyId())){
                ids.add(res.getModifyId());
            }
        }
        Iterable<User> usersIterable = userRepository.findAll(ids);

        Map<String, String> userNameMap = new HashMap<String, String>();
        if (usersIterable != null) {
            for (User user : usersIterable) {
                userNameMap.put(user.getId(), user.getAccount());
            }
        }
        //深度拷贝对象信息并存储
        for (Resource res : resList) {
            ResourceVo resVo = new ResourceVo();
            try {
                BeanUtil.copyAllProperties(res, resVo);
            } catch (Exception e) {
                log.error("资源PO对象转VO对象错误，资源信息："+ JSONObject.fromObject(res));
                e.printStackTrace();
            }
            resVo.setUserAccount(userNameMap.get(res.getModifyId()));
            resVoList.add(resVo);
        }
        return resVoList;
    }
}
